#include "server_transfile.h"
// 定义命令类型
//typedef enum {
//    // 基本命令
//    CMD_CD = 0x01,          // 改变目录
//    CMD_LS = 0x02,          // 列出目录
//    CMD_PWD = 0x03,         // 当前工作目录
//
//    // 文件操作命令
//    CMD_PUTS = 0x10,        // 上传文件
//    CMD_GETS = 0x11,        // 下载文件
//    CMD_REMOVE = 0x12,      // 删除文件
//    CMD_MKDIR = 0x13,       // 创建目录
//    CMD_RMDIR = 0x14,       // 删除目录
//
//    // 大文件传输命令
//    CMD_FILE_START = 0x20,  // 文件传输开始
//    CMD_FILE_DATA = 0x21,   // 文件数据块
//    CMD_FILE_END = 0x22,    // 文件传输结束
//
//    // 响应和错误
//    CMD_RESPONSE = 0x30,    // 正常响应
//    CMD_ERROR = 0xFF        // 错误响应
//} CommandType;
//
//// TLV协议头大小 (type + length + seq + checksum)
//#define TLV_HEADER_SIZE 13
//
//// TLV结构体
//typedef struct {
//    uint8_t type;           // 命令类型 (1字节)
//    uint32_t length;        // 数据长度 (4字节)
//    uint32_t seq;           // 可选。。。序列号 (4字节)
//    char value[1024];           // 数据长度（文件？）
//} TLV;
/* Usage:  */
int send_all(int sockfd,const void *buf,size_t len){
    size_t total=0;
    const char*p=(const char*)buf;
    while(total<len){
        ssize_t n=send(sockfd,p+total,len-total,0);
        total+=n;
    }
    return 0;
}
//发送tlv
int sendTlv(int sockfd,TLV *tlv){
    char buf[TLV_HEADER_SIZE];
    buf[0]=tlv->type;
    memcpy(buf+1,&tlv->seq,4);
    memcpy(buf+5,&tlv->length,4);
    if(send_all(sockfd,buf,sizeof(buf))!=0){
        return -1;
    }
    if(tlv->length>0){
        return send_all(sockfd,tlv->value,tlv->length);
    }
    return 0;
}

int recv_all(int sockfd,void *buf,size_t len){
    size_t total=0;
    char *p=(char*)buf;
    while(total<len){
        ssize_t n=recv(sockfd,p+total,len-total,0);
        total+=n;
    }
    return 0;
}
//计算hash
int hash_count(const char *filename,char *hash_str){
    SHA256_CTX ctx;
    SHA256_Init(&ctx);
    char buf[4096];
    int fd=open(filename,O_RDWR);
    while(1){
        bzero(buf,sizeof(buf));
        ssize_t sret=read(fd,buf,sizeof(buf));
        SHA256_Update(&ctx,buf,sret);
        if(sret==0){
            break;
        }
    }
    unsigned char sha[32];
    SHA256_Final(sha,&ctx);
    for(int i=0;i<32;i++){
        char temp[3]={0};
        sprintf(temp,"%02x",sha[i]);
        strcat(hash_str,temp);
    }
    return 0;
}

//接收tlv
int recvTlv(int sockfd,TLV* tlv){
    char buf[TLV_HEADER_SIZE];
    recv_all(sockfd,buf,sizeof(buf));
    tlv->type=buf[0];
    memcpy(&tlv->seq,buf+1,4);
    memcpy(&tlv->length,buf+5,4);
    if(tlv->length>0){
        recv_all(sockfd,tlv->value,tlv->length);
    }
    return 0;
}
int recvFile(int netfd,TLV*tlv,MYSQL*mysql,fileMetaData_t*meta){
    char filename[1024];
    strncpy(filename,tlv->value,sizeof(filename)-1);
    filename[sizeof(filename)-1]='\0';
    TLV file_header;//接收文件大小
    recvTlv(netfd,&file_header);
    if(file_header.type!=CMD_FILE_START){
        return -1;
    }
    uint32_t file_size;
    memcpy(&file_size,file_header.value,file_header.length);
    int fd=open(filename,O_WRONLY|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(fd,-1,"open");
    file_size = ntohl(file_size);
    uint64_t total_receive=0;
    char buff[4096];
    while(total_receive<file_size){
        size_t to_receive;
        size_t remaining=file_size-total_receive;
        if (remaining > sizeof(buff)) {
            to_receive = sizeof(buff);
        } else {
            to_receive = remaining;
        }
        ssize_t n=recv(netfd,buff,to_receive,0);

        write(fd,buff,n);
        total_receive+=n;
        double progress = (double)total_receive / file_size * 100;
        printf("Progress: %.1f%%\r", progress);
        fflush(stdout);
    }
    TLV end_tlv;//接收文件的hash值
    memset(&end_tlv, 0, sizeof(TLV));
    recvTlv(netfd, &end_tlv);
    if(end_tlv.type==CMD_FILE_END){
        printf("\n文件上传结束\n");
    }
    printf("\n文件上传 %s: %ld/%d 字节\n",
           (total_receive == file_size) ? "完成" : "失败",
           total_receive, file_size);
    printf("哈希:%s\n",end_tlv.value);
    strncpy(meta->hash,end_tlv.value,sizeof(meta->hash));
    meta->file_type=2;
    char hash_str[65]={0};
    hash_count(filename,hash_str);//校验hash
    if(strcmp(meta->hash,hash_str)!=0){
        printf("经过校验，hash值不匹配,请重传\n");
        unlink(filename);//删除文件
        close(fd);
        return -1;
    }
    printf("校验后,hash值一致\n");
    insert_into(mysql,meta);
    close(fd);
    return 0;

}
//发送客户端需要的文件
int getFile(int netfd,TLV*tlv){
    char filename[1024];
    if (tlv->length < sizeof(filename)) {
        strncpy(filename, tlv->value, tlv->length);
        filename[tlv->length] = '\0';
    }
    printf("收到下载请求: %s\n", filename);
    struct stat st;
    int fd = open(filename, O_RDONLY);
    ERROR_CHECK(fd,-1,"open");
    fstat(fd,&st);
    uint32_t file_size = st.st_size;
    uint32_t net_file_size = htonl(file_size);
    TLV start_tlv;
    memset(&start_tlv,0,sizeof(TLV));
    start_tlv.type = CMD_FILE_START;
    printf("filesize=%ld\n",st.st_size);
    memcpy(start_tlv.value, &net_file_size, sizeof(net_file_size));
    start_tlv.length = sizeof(net_file_size);
    printf("Sending file: %s (%u bytes)\n", filename, file_size);
    off_t total_sent = 0;
    off_t offset = 0;
    sendTlv(netfd,&start_tlv);
    while (total_sent < file_size) {
        ssize_t sent = sendfile(netfd, fd, &offset, file_size - total_sent);
        total_sent += sent;
        double progress = (double)total_sent / file_size * 100;
        printf("Get progress: %.1f%%\r", progress);
        fflush(stdout);
    }
    TLV end_tlv;
    memset(&end_tlv, 0, sizeof(TLV));
    end_tlv.type = CMD_FILE_END;
    end_tlv.length = sizeof(total_sent);
    sendTlv(netfd, &end_tlv);
    printf("\n文件发送 %s: %ld/%d 字节\n",
           (total_sent == file_size) ? "完成" : "失败",
           total_sent, file_size);

    close(fd);
    return 0;
}
//检测文件的hash
int check_file_hash(int netfd,TLV*tlv,MYSQL*mysql){
    TLV response;
    memset(&response,0,sizeof(TLV));
    char sql[128];
    snprintf(sql, sizeof(sql),
                  "SELECT hash FROM userfile WHERE hash='%s'",
                  tlv->value);//将value的值拼接到字符串中
    int qret=mysql_query(mysql,sql);
    if (qret != 0) {
    fprintf(stderr, "查询失败:%s\n", mysql_error(mysql));
    return 0;
    }
    MYSQL_RES *result = mysql_store_result(mysql);
    if(result!=NULL){
        if(mysql_num_rows(result)>0){
        response.type=CMD_FILE_EXISTS;
        sendTlv(netfd,&response);
        printf("已有重复文件\n");
        mysql_free_result(result);
        return -1;
        }
        mysql_free_result(result);
        response.type=CMD_RESPONSE;
        sendTlv(netfd,&response);
        printf("无重复文件\n");
    }
        return 0;
}
//int main(int argc, char *argv[]){                                  
//    ARGS_CHECK(argc,3);
//    int sockfd = socket(AF_INET,SOCK_STREAM,0);
//    int flag = 1;
//    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
//    struct sockaddr_in addr;
//    addr.sin_family = AF_INET;
//    addr.sin_port = htons(atoi(argv[2]));
//    addr.sin_addr.s_addr = inet_addr(argv[1]);
//    int ret = bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));
//    ERROR_CHECK(ret,-1,"bind");
//    listen(sockfd,50);
//    int netfd=accept(sockfd,NULL,NULL);
//    MYSQL *mysql=mysql_init(NULL);
//    MYSQL *qet=mysql_real_connect(mysql,"localhost","root","!Sy184360","66test",0,NULL,0);
//    if(qet==NULL){
//        fprintf(stderr,"%s:%d\n","mysql_real_connect",mysql_errno(mysql));
//        exit(-1);
//    }
//    while (1) {
//        TLV tlv;
//        memset(&tlv, 0, sizeof(TLV));
//        if (recvTlv(netfd, &tlv) != 0) {
//            perror("接收命令失败");
//            break;
//        }
//
//        printf("收到命令: type=0x%02X, length=%u, value=%.*s\n", 
//               tlv.type, tlv.length, (int)tlv.length, tlv.value);
//
//        switch (tlv.type) {
//        case CMD_CD:
//            printf("处理CD命令: %s\n", tlv.value);
//            // 实现CD命令逻辑...
//            break;
//        case CMD_FILE_CHECK:
//            printf("检测是否有重复文件\n");
//            if(check_file_hash(netfd,&tlv,mysql)!=0){
//                perror("文件重复\n");
//            }
//            break;
//        case CMD_PUTS:
//            printf("处理PUTS命令\n");
//            if (recvFile(netfd, &tlv,meta) != 0) {
//                perror("文件接收失败");
//            }
//            break;
//
//        case CMD_GETS:
//            printf("处理GETS命令\n");
//            if (getFile(netfd, &tlv) != 0) {
//                perror("文件发送失败");
//            }
//            break;
//
//        case CMD_FILE_START:
//        case CMD_FILE_END:
//            // 这些包应该在文件处理函数内部处理
//            fprintf(stderr, "错误: 在主循环接收到文件传输包\n");
//            break;
//
//        default:
//            fprintf(stderr, "未知命令: 0x%02X\n", tlv.type);
//            break;
//        }
//    }
//    mysql_close(mysql);
//    close(sockfd);
//    close(netfd);
//    return 0;
//
//}

